﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//    OutlookUtilsTest.cs
//
// Abstract:
//
//    Unit tests for OutlookUtils class
//
//--

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EnhancedReminders.Properties;
using Microsoft.Office.Interop.Outlook;
using Microsoft.OfficeCommunicationsServer.Applications.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.EnhancedReminders.OutlookAddIn.UnitTests
{
    /// <summary>
    ///This is a test class for OutlookUtilsTest and is intended
    ///to contain all OutlookUtilsTest Unit Tests
    ///</summary>
    [TestClass()]
    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
    Justification = "Class name reflect type name being tested")]
    public class OutlookUtilsTest
    {
        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        /// <summary>
        ///A test for SaveAttachment
        ///</summary>
        [TestMethod()]
        public void SaveAttachmentTest()
        {
            MockAttachments attachments = new MockAttachments(typeof(ReminderItem));
            Debug.Assert(attachments != null, "attachments != null");

            ReminderItem reminderItem = new ReminderItem(new List<NotificationChannel>());
            Debug.Assert(reminderItem != null, "reminderItem != null");
            reminderItem.NotificationChannelList.Channels.Add(new NotificationChannel());

            object initial = OutlookUtils_Accessor.LoadAttachment(attachments);
            Assert.AreEqual(null, initial, "Attachments should be initially empty");

            OutlookUtils_Accessor.SaveAttachment(attachments, reminderItem);
            object actual = OutlookUtils_Accessor.LoadAttachment(attachments);
            Assert.IsTrue(actual is ReminderItem, "Object is of type ReminderItem");
        }

        /// <summary>
        ///A test for RemoveAttachment
        ///</summary>
        [TestMethod()]
        public void RemoveAttachmentTest()
        {
            MockAttachments attachments = new MockAttachments(typeof(ReminderItem));
            Debug.Assert(attachments != null, "attachments != null");

            OutlookUtils_Accessor.RemoveAttachment(attachments);

            foreach (Attachment attachment in attachments)
            {
                if (attachment.FileName == Constants.AttachmentName)
                {
                    Assert.Fail("Attachment not deleted");
                }
            }
        }

        /// <summary>
        ///A test for LoadAttachment
        ///</summary>
        [TestMethod()]
        public void LoadAttachmentFromEmptyAttachmentsTest()
        {
            MockAttachments attachments = new MockAttachments(typeof(ReminderItem));
            Debug.Assert(attachments != null, "attachments != null");

            object expected = null; 
            object actual;
            actual = OutlookUtils_Accessor.LoadAttachment(attachments) as ReminderItem;
            Assert.AreEqual(expected, actual, "Attachment shouldn't have any ReminderItem");
        }

        /// <summary>
        /// Test for creating the default Notification rules
        /// </summary>
        [TestMethod]
        public void DefaultRulesTest()
        {
            NotificationRules defaultRules =  OutlookUtils_Accessor.CreateDefaultRules(new ObservableCollection<NotificationChannel>());

            Assert.IsTrue(defaultRules.Count == 2, "defaultRules.RulesItems.Count == 2");

            foreach (NotificationRuleItem rule in defaultRules)
            {
                if (rule.RuleName == Resources.DefaultOffHoursRuleName)
                {
                    NotificationTimeCondition timeCondition = Helpers.AssertCast<NotificationTimeCondition>(rule.GetCondition(typeof(NotificationTimeCondition)));
                    Assert.IsNotNull(timeCondition, "condition is NotificationTimeCondition");
                    Assert.IsTrue(timeCondition.TimeArray.Length == NotificationTimeCondition.IntervalsPerDay * NotificationTimeCondition.NumberOfDays, "timeCondition.TimeArray.Length == NotificationTimeCondition.IntervalsPerDay * NotificationTimeCondition.NumberOfDays");

                    // Sunday should be true the whole day
                    for (int i = 0; i <= NotificationTimeCondition.IntervalsPerDay; i++)
                    {
                        Assert.IsTrue(timeCondition.TimeArray[i], "Sunday is set to true the whole day");
                    }

                    // Saturday should be true the whole day
                    for (int j = NotificationTimeCondition.IntervalsPerDay * NotificationTimeCondition.NumberOfDays - 1;
                        j >= NotificationTimeCondition.IntervalsPerDay * NotificationTimeCondition.NumberOfDays - NotificationTimeCondition.IntervalsPerDay;
                        j--)
                    {
                        Assert.IsTrue(timeCondition.TimeArray[j], "Saturday is set to true the whole day");
                    }

                    // BitArray starts on Sunday 12am. Each bit represents a 1/2 hour slot, i.e. 
                    // the first bit represents 12am-12.30am. 
                    // 8am-8.30am would be presented by the 17th bit and
                    // 5.30pm-6pm would be represented by the 36th bit.
                    // When we index into the BitArray, we have to -1 to account for the 0-based index
                    int eightInTheMorning = 17;
                    int sixInTheEvening = 36;

                    // Weekdays should be true the whole day, except for office hours
                    for (int day = 1; day <= 5; day++)
                    {
                        for (int k = day * NotificationTimeCondition.IntervalsPerDay; k < (day + 1) * NotificationTimeCondition.IntervalsPerDay; k++)
                        {
                            if (k < day * NotificationTimeCondition.IntervalsPerDay + eightInTheMorning - 1 || k > day * NotificationTimeCondition.IntervalsPerDay + sixInTheEvening - 1)
                            {
                                Assert.IsTrue(timeCondition.TimeArray[k], "Weekdays should be true outside office hours");
                            }
                            else
                            {
                                Assert.IsFalse(timeCondition.TimeArray[k], "Weekdays should be false during office hours");
                            }
                        }
                    }
                }
                else
                {
                    Assert.AreEqual<string>(Resources.DefaultVoicemailsAwayRuleName, rule.RuleName, "Away rule is one of the default");

                    NotificationStatusCondition statusCondition = Helpers.AssertCast<NotificationStatusCondition>(rule.GetCondition(typeof(NotificationStatusCondition)));
                    Assert.IsTrue(statusCondition.Presence == (PresenceStates.Away | PresenceStates.BeRightBack | PresenceStates.IdleBusy | PresenceStates.IdleOnline | PresenceStates.Offline), "statusCondition.Presence == PresenceBits.Unknown");
                }
            }
        }

        /// <summary>
        /// Test for TimeZone conversions
        /// </summary>
        [TestMethod]
        public void SimpleGetFirstMatchingRuleTest()
        {
            NotificationRules defaultRules = OutlookUtils_Accessor.CreateDefaultRules(new ObservableCollection<NotificationChannel>());
            defaultRules.TimeZone = "Pacific Standard Time";

            // Active default rules
            foreach (NotificationRuleItem rule in defaultRules)
            {
                rule.IsEnabled = true;
            }

            NotificationData data = new NotificationData("john@contoso.com", MailboxType.Voicemail, new DateTime(2007, 9, 22, 10, 0, 0));
            NotificationRuleItem[] matchingRules = defaultRules.GetMatchingRules(data);

            Assert.IsNotNull(matchingRules, "Should match default rules");
            Assert.AreEqual<int>(2, matchingRules.Length, "Should match default rules");

            ReminderItem[] reminderItems = NotificationRuleItem.CreateReminderItems(matchingRules);

            Assert.IsNotNull(reminderItems, "Default rules should match away voicemail rule");
            Assert.AreEqual<PresenceStates>(
                PresenceStates.Away | PresenceStates.IdleBusy | PresenceStates.IdleOnline | PresenceStates.BeRightBack | PresenceStates.Offline, reminderItems[0].Presence, 
                "When a time condition is satisfied, presence information shouldn't be set");
            Assert.AreEqual<PresenceStates>(PresenceStates.None, reminderItems[1].Presence, 
                "When a time condition is satisfied, presence information shouldn't be set");
        }

        /// <summary>
        /// Simple test for Off Hours rule
        /// </summary>
        [TestMethod]
        public void OffHoursRuleTest()
        {
            NotificationRules defaultRules = OutlookUtils_Accessor.CreateDefaultRules(new ObservableCollection<NotificationChannel>());
            defaultRules.TimeZone = "Pacific Standard Time";

            // Active Off hours rule
            foreach (NotificationRuleItem rule in defaultRules)
            {
                if (rule.RuleName == Resources.DefaultOffHoursRuleName)
                {
                    rule.IsEnabled = true;
                    foreach (NotificationCondition condition in rule.Conditions)
                    {
                        if (condition is NotificationTimeCondition)
                        {
                            condition.IsSelected = true;
                        }
                    }
                }
            }

            // Sunday, 8am
            DateTime weekend = new DateTime(2007, 9, 23, 15, 0, 0);
            // Monday 7.55am
            DateTime mondayMorning = new DateTime(2007, 9, 24, 14, 55, 0);
            // Tuesday 8.01am
            DateTime tuesdayOfficeHours = new DateTime(2007, 9, 25, 15, 1, 0);

            NotificationData data = new NotificationData("john@contoso.com", MailboxType.Voicemail, weekend);
            Assert.IsNotNull(defaultRules.GetMatchingRules(data), "Weekend voicemail should trigger rule");

            data = new NotificationData("john@contoso.com", MailboxType.Voicemail, mondayMorning);
            Assert.IsNotNull(defaultRules.GetMatchingRules(data), "Voicemail on Monday morning before office hours should trigger rule");

            data = new NotificationData("john@contoso.com", MailboxType.Voicemail, tuesdayOfficeHours);
            Assert.IsNull(defaultRules.GetMatchingRules(data), "Voicemail on Tuesday during office hours shouldn't trigger rule");
        }


    }
}
